
#include <cblas.h>
#include <cmath>
#include <cstring>
#include <stdint.h>

void performance(int m, int n, int k, bool is_integer, double avg_time) {
  double total_ops = double(m) * double(n) * double(k) * 2;
  double perf = (total_ops / avg_time) * 1e-9;

  auto scale_string = "G";
  auto unit_string = is_integer ? "OP/s" : "FLOP/s";

  if (perf >= 1000) {
    perf /= 1000;
    scale_string = "T";
  }

  printf("%lf %s%s\n", perf, scale_string, unit_string);
}

int8_t float2int8(float f, float scale) {
  int8_t i = int8_t(f * scale);
  if (i < -127)
    i = -127;
  if (i > 127)
    i = 127;
  return i;
}

float fp16_to_fp32(uint16_t fp16) {
  uint32_t sign = (fp16 >> 15) & 0x1;
  uint32_t exponent = (fp16 >> 10) & 0x1F;
  uint32_t mantissa = fp16 & 0x3FF;

  if (exponent == 0) {
    if (mantissa == 0) {

      return sign ? -0.0f : 0.0f;
    } else {

      while ((mantissa & 0x400) == 0) {
        mantissa <<= 1;
        exponent--;
      }
      mantissa &= 0x3FF;
      exponent++;
    }
  } else if (exponent == 0x1F) {
    if (mantissa == 0) {

      return sign ? -INFINITY : INFINITY;
    } else {

      return sign ? -NAN : NAN;
    }
  }

  int32_t exp32 = exponent - 15 + 127;
  uint32_t mantissa32 = mantissa << 13;

  uint32_t fp32_bits = (sign << 31) | (exp32 << 23) | mantissa32;

  float result;
  std::memcpy(&result, &fp32_bits, sizeof(float));
  return result;
}